﻿// @brief
// @file SVDDocument.cs
// @date 2024年08月16日
// @author doublecat
// 
// Copyright (C) &lt;2024&gt;  &lt;doublecat&gt;
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

using System.Xml;
using System.Xml.Serialization;

namespace doublecat.mcu.svd;

/// <summary>
/// SVD文档定义
/// </summary>
public class SVDDocument {
    private readonly XmlDocument _xml = new();

    private Device? _device;

    /// <summary>
    /// 空文档构造函数
    /// </summary>
    public SVDDocument() : this(string.Empty) {
    }


    /// <summary>
    /// 文档构造函数
    /// </summary>
    public SVDDocument(string fileName) {
        if (!string.IsNullOrEmpty(fileName))
            Load(fileName);
    }

    /// <summary>
    /// 返回设备对象
    /// </summary>
    /// <returns></returns>
    /// <exception>
    /// 如果设备为空则抛出此异常！
    ///     <cref>exception</cref>
    /// </exception>
    public Device GetDevice() {
        return _device ?? throw new Exception("Device is null");
    }

    /// <summary>
    /// 清除文档数据
    /// </summary>
    public void Clear() {
        GC.Collect();
    }

    /// <summary>
    /// 查找指定名称的设备
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public Peripheral? FindPeripheral(string name) {
        return GetDevice().Peripherals.FirstOrDefault(p => p.Name == name);
    }

    /// <summary>
    /// 加载指定路径的SVD文档
    /// </summary>
    /// <param name="path">svd文档路径，包括文件名</param>
    /// <returns></returns>
    /// <exception cref="NullReferenceException"></exception>
    public SVDDocument Load(string path) {
        if (!string.IsNullOrEmpty(path)) {
            XmlSerializer    serializer = new XmlSerializer(typeof(Device));
            using FileStream fs         = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
            _device = serializer.Deserialize(fs) as Device;
            if (_device == null)
                throw new Exception("read svd documents failure!");
            // 初始化Peripheral
            foreach (Peripheral peripheral in GetDevice()!.Peripherals) {
                // 设置Peripheral所属设备
                peripheral.Parent = GetDevice();
                foreach (Register register in peripheral.Registers) {
                    // 设置Register所属外设
                    register.Parent = peripheral;
                    foreach (Field field in register.Fields) {
                        // 设置Field所属寄存器
                        field.Parent = register;
                        // 枚举初始化
                        if (field.Enumerated != null) {
                            field.Enumerated.Parent = field;
                            foreach (EnumeratedValue enumeratedValue in field.Enumerated.EnumeratedValues) {
                                enumeratedValue.Parent = field.Enumerated;
                            }
                        }
                    }
                }
            }
            return this;
        }
        throw new Exception("path is null");
    }
}
